﻿// <com.woyouqiu.Copyright>
// --------------------------------------------------------------
// <copyright>上海有求网络科技有限公司 2015</copyright>
// <Solution>Vecen.BangChuang</Solution>
// <Project>Vecen.BangChuang.Net.Sms</Project>
// <FileName>RongLianSmsSender.cs</FileName>
// <CreateTime>2017-04-29 21:21</CreateTime>
// <Author>何苗</Author>
// <Email>hemiao@woyouqiu.com</Email>
// <log date="2017-04-29 21:21" version="00001">创建</log>
// --------------------------------------------------------------
// </com.woyouqiu.Copyright>

using System;
using System.Collections.Generic;
using System.Net;
using System.Net.Http;
using System.Net.Http.Headers;
using System.Security.Cryptography;
using System.Text;
using System.Threading.Tasks;
using Abp.Domain.Repositories;
using Abp.Json;
using Abp.Logging;
using Abp.Threading;
using Abp.UI;
using Newtonsoft.Json;
using Vecen.BangChuang.Net.Sms;

namespace Vecen.BangChuang.SmsImpts {
    public class RongLianSmsSender: SmsSenderBase {
        public RongLianSmsSender(ISmsSenderConfiguration configuration,
            IRepository<SmsMessage> smsRepository): base(configuration) {
            _smsRepository = smsRepository;
        }

        private readonly IRepository<SmsMessage> _smsRepository;

        protected override async Task SendSmsAsync(SmsMessageDto sms) {
            SmsMessage entity = new SmsMessage();
            entity.ReceiverPhone = sms.ReceiverPhone;
            entity.TemplateCode = sms.TemplateCode;
            entity.TemplateParams = string.Join("|", sms.TemplateParams);
            entity.FreeSignName = sms.FreeSignName;

            HttpClient httpClient = new HttpClient();
            DateTime sendTime = DateTime.Now;
            httpClient.DefaultRequestHeaders.Accept.Add(new MediaTypeWithQualityHeaderValue("application/json"));
            httpClient.DefaultRequestHeaders.TryAddWithoutValidation("Authorization",
                new List<string>() {GetAuthentication(sendTime)});
            var urlString = _configuration.GetServiceUrl();
            urlString = urlString.Replace("{accountSid}", _configuration.GetAccountId());
            urlString = urlString.Replace("{SigParameter}", GetSignature(sendTime));

            RongLianSmsRequestBody requestBody = new RongLianSmsRequestBody();
            requestBody.AppId = _configuration.GetAppKey();
            requestBody.To = sms.ReceiverPhone;
            requestBody.TemplateId = sms.TemplateCode;
            requestBody.Datas = sms.TemplateParams;
            HttpContent content = new StringContent(requestBody.ToJsonString(true));
            content.Headers.ContentType = new MediaTypeHeaderValue("application/json");
            content.Headers.ContentEncoding.Add("utf-8");
            var response = await httpClient.PostAsync(urlString, content);
            if(response.StatusCode != HttpStatusCode.OK) {
                entity.IsSuccess = false;
                await _smsRepository.InsertAndGetIdAsync(entity);
                LogHelper.Logger.ErrorFormat("短信发送失败!{0}", await response.Content.ReadAsStringAsync());
                throw new UserFriendlyException("请求失败!", "短信发送失败!");
            }
            var responseContent = await response.Content.ReadAsStringAsync();
            RongLianSmsResponseBody responseBody =
                JsonConvert.DeserializeObject<RongLianSmsResponseBody>(responseContent);
            if(responseBody.StatusCode != "000000") {
                entity.IsSuccess = false;
                await _smsRepository.InsertAndGetIdAsync(entity);
                LogHelper.Logger.ErrorFormat("短信发送失败!{0}", await response.Content.ReadAsStringAsync());
                throw new UserFriendlyException("请求失败!", "短信发送失败!");
            }

            entity.IsSuccess = true;
            entity.RequestSmsUid = responseBody.TemplateSMS.SmsMessageSid;
            await _smsRepository.InsertAndGetIdAsync(entity);
        }

        private string GetSignature(DateTime sendTime) {
            var accountId = _configuration.GetAccountId();
            var accountToken = _configuration.GetAccountToken();
            var timestamp = sendTime.ToString("yyyyMMddHHmmss");

            MD5 md5Hasher = MD5.Create();
            byte[] data = md5Hasher.ComputeHash(Encoding.UTF8.GetBytes(accountId + accountToken + timestamp));
            StringBuilder sBuilder = new StringBuilder();

            // Loop through each byte of the hashed data and format each one as a hexadecimal string.
            for(int i = 0; i < data.Length; i++) {
                sBuilder.Append(data[i].ToString("X2"));
            }

            // Return the hexadecimal string.
            return sBuilder.ToString();
        }

        private string GetAuthentication(DateTime sendTime) {

            var accountId = _configuration.GetAccountId();
            byte[] data = Encoding.UTF8.GetBytes(accountId + ":" + sendTime.ToString("yyyyMMddHHmmss"));
            return Convert.ToBase64String(data);
        }

        protected override void SendSms(SmsMessageDto sms) {
            AsyncHelper.RunSync(() => SendSmsAsync(sms));
        }
    }

    class RongLianSmsRequestBody {
        public string To { get; set; }

        public string AppId { get; set; }

        public string TemplateId { get; set; }
        public List<string> Datas { get; set; }
    }

    class RongLianSmsResponseBody {
        public string StatusCode { get; set; }

        public RongLianSmsTemplateSMS TemplateSMS { get; set; }
    }

    class RongLianSmsTemplateSMS {
        public string SmsMessageSid { get; set; }

        public string DateCreated { get; set; }
    }
}